Skip to content

[SSH] Fail fast when the driver proxy refuses the tunnel - #7057

Merged
anton-107 merged 3 commits into
mainfrom
ssh-fail-fast-driver-proxy-forbidden
Oct 15, 2026
Merged

anton-107 merged 3 commits into
mainfrom
ssh-fail-fast-driver-proxy-forbidden

Conversation

@anton-107

@anton-107 anton-107 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Changes

databricks ssh connect now stops at the first 403 from the driver proxy and prints the proxy's own message, instead of polling /metadata until the 5-minute server start timeout. It also cancels the run it submitted, since no client can ever reach that server.

Starting SSH server...
Job submitted successfully with run ID: 1035981371775948
Error: failed to ensure that ssh server is running: the workspace refused the SSH tunnel connection: FEATURE_DISABLED: An administrator has disabled port forwarding to serverless compute for this workspace, which includes the SSH tunnel used by `databricks ssh connect`
  • getServerMetadata turns a 403 into the new errDriverProxyForbidden, carrying the response body with its JSON quotes removed. It isn't joined with errServerMetadata, so the first call (the reuse path) returns it as is instead of submitting a new server.
  • The wait loop returns that error immediately and cancels its own run, best effort (cancelSSHServerRun). A server found running on the reuse path is never cancelled.
  • Every other non-200 is still retried, for example 400 INVALID_STATE from a metadata.json that points at a terminated cluster.
  • libs/testserver gains a settings v2 PATCH handler, and its fake driver proxy returns the real FEATURE_DISABLED body while port_fwd_serverless_enabled is false.

Why

When an administrator turns off port_fwd_serverless_enabled, the driver proxy answers every request to the tunnel server with 403 and the body "FEATURE_DISABLED: …" (a JSON string, not the usual error object). The client counted any non-200 as "server not up yet", so the user watched "Waiting for the SSH server to start..." for 5 minutes and then got server is not ok, status code 403, while the serverless compute stayed up.

This is PR 1 of DECO-28889. PR 2 adds a check of port_fwd_serverless_enabled before any compute is started, with this 403 handling as the fallback when the setting can't be read. PR 3 adds telemetry error categories for both.

Tests

  • Unit: TestMetadataResponseError covers a 403 with the real body, a non-JSON body and an empty body, plus a 400 and a 502 that are still retried.
  • Acceptance: new acceptance/ssh/connect-serverless-feature-disabled turns the setting off through the API, then checks the error and the recorded runs/cancel. It finishes in 1.6 s, so connect gives up on the first 403. All other acceptance/ssh tests still pass.
  • Manual, dogfood (setting off): serverless CPU failed after 31 s with the message above, most of it uploading binaries. Run 1035981371775948 ended TERMINATED / CANCELED.
  • Manual, dogfood: a dedicated cluster (0907-190337-c3qelmbu) still connects and runs the remote command.

This pull request and its description were written by Isaac.

When an administrator disables port forwarding to serverless compute, the
driver proxy answers every request to the tunnel server with 403
FEATURE_DISABLED. ssh connect treated that like a server that was still
starting, kept polling /metadata for the full 5-minute timeout, and then
failed with a generic "status code 403" error while the compute it had
started stayed up.

A 403 from /metadata is now final: connect stops on the first one with the
proxy's own message, both in the wait loop and on the reuse path (where it
would otherwise submit another server), and cancels the run it submitted.
Every other non-200, such as 400 INVALID_STATE from a stale metadata.json,
is still retried.

The test server models the port_fwd_serverless_enabled setting so the
acceptance test reaches the 403 through the setting rather than a stub.

DECO-28889

Co-authored-by: Isaac <no-reply@databricks.com>
@anton-107
anton-107 requested review from a team as code owners October 14, 2026 15:01
anton-107 and others added 2 commits October 14, 2026 15:02
Co-authored-by: Isaac <no-reply@databricks.com>
The settings v2 backend decodes the PATCH body as a protobuf message, in
which false is the default, so {"boolean_val": {"value": false}} arrives
empty and is rejected with "must contain at least one subfield with a
non-default value" (seen on dogfood). The fake accepted it, so the
acceptance test turned the setting off with a request the real API
refuses. The fake now rejects it the same way, and the test sends the
name in the body, which is what the real API needs.

Co-authored-by: Isaac <no-reply@databricks.com>
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 86d1e8b

Run: 38587563731

Env 🔄​flaky ✅​pass 🙈​skip Time
✅​ aws linux-2core-8gb 276 16 10:23
🔄​ aws-windows-latest-4core-16gb 1 277 14 7:36
✅​ azure linux-2core-8gb 275 16 12:00
✅​ azure-windows-latest-4core-16gb 277 14 8:18
✅​ gcp linux-2core-8gb 276 16 8:30
✅​ gcp-windows-latest-4core-16gb 278 14 10:31
Test Name aws-windows-latest-4core-16gb
🔄​ TestSyncIncrementalFileOverwritesFolder 🔄​f
Top 10 slowest tests (at least 2 minutes):
duration env testname
4:51 gcp-windows-latest-4core-16gb TestAccept
3:54 gcp linux-2core-8gb TestFilerWorkspaceFilesExtensionsStat
3:44 azure linux-2core-8gb TestImportDirDoesNotOverwrite
3:17 gcp-windows-latest-4core-16gb TestFilerWorkspaceFilesExtensionsReadDir
3:08 aws-windows-latest-4core-16gb TestAccept
3:07 azure-windows-latest-4core-16gb TestAccept
3:03 aws-windows-latest-4core-16gb TestImportDirDoesNotOverwrite
2:35 gcp-windows-latest-4core-16gb TestImportDirWithOverwriteFlag
2:34 aws-windows-latest-4core-16gb TestFilerWorkspaceFilesExtensionsReadDir
2:28 aws linux-2core-8gb TestFilerWorkspaceFilesExtensionsReadDir

@anton-107
anton-107 enabled auto-merge October 15, 2026 12:11
@anton-107
anton-107 added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit 4d4ed66 Oct 15, 2026
28 checks passed
@anton-107
anton-107 deleted the ssh-fail-fast-driver-proxy-forbidden branch October 15, 2026 13:52
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 4d4ed66

Run: 38746584615

Env ❌​FAIL 🔄​flaky ✅​pass 🙈​skip Time
❌​ aws linux-2core-8gb 4 1425 1161 123:36
❌​ aws-windows-latest-4core-16gb 4 1350 1186 148:27
❌​ azure linux-2core-8gb 4 2 1272 1213 109:14
❌​ azure-windows-latest-4core-16gb 4 8 1191 1238 137:59
❌​ gcp linux-2core-8gb 4 2 1261 1217 111:29
❌​ gcp-windows-latest-4core-16gb 4 1188 1242 124:18
16 interesting tests: 12 flaky, 4 FAIL
Test Name aws linux-2core-8gb aws-windows-latest-4core-16gb azure linux-2core-8gb azure-windows-latest-4core-16gb gcp linux-2core-8gb gcp-windows-latest-4core-16gb
❌​ TestAccept ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
🔄​ TestAccept/bundle/invariant/destroy_idempotent ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=cluster_libraries.yml.tmpl/READPLAN= ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/invariant/no_drift ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
🔄​ TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=cluster_apply_policy_default_values.yml.tmpl/READPLAN= ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
🔄​ TestAccept/bundle/resources/registered_models/basic ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
🔄​ TestAccept/bundle/resources/registered_models/basic/DMS=true ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
❌​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name/DMS= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name/DMS=true ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
🔄​ TestAccept/bundle/templates/default-python/combinations/classic ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/combinations/classic/DLT=yes/DMS=/NBOOK=no/PY=yes/READPLAN=1 ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/integration_classic ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/integration_classic/DMS=/UV_PYTHON=3.10 ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
🔄​ TestFsCpDir ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p
🔄​ TestFsCpDir/uc-volumes_to_local ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p
Top 50 slowest tests (at least 2 minutes):
duration env testname
14:01 azure-windows-latest-4core-16gb TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=cluster_apply_policy_default_values.yml.tmpl/READPLAN=1
8:13 aws linux-2core-8gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=
8:03 aws-windows-latest-4core-16gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=
7:52 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/deploy/local_ssd_count/DMS=true
7:48 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/deploy/local_ssd_count/DMS=
7:45 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/deploy/data_security_mode/DMS=true
7:27 gcp linux-2core-8gb TestAccept/bundle/resources/clusters/deploy/local_ssd_count/DMS=true
7:22 gcp linux-2core-8gb TestAccept/bundle/config-remote-sync/multiple_resources/DMS=
7:08 aws linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=true
7:05 aws linux-2core-8gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=true
7:04 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=
7:04 aws-windows-latest-4core-16gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=true
7:03 gcp linux-2core-8gb TestAccept/bundle/resources/clusters/deploy/local_ssd_count/DMS=
7:01 azure-windows-latest-4core-16gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=true
6:57 gcp linux-2core-8gb TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=cluster_apply_policy_default_values.yml.tmpl/READPLAN=
6:56 azure linux-2core-8gb TestAccept/bundle/config-remote-sync/multiple_resources/DMS=true
6:56 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=true
6:54 azure-windows-latest-4core-16gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=
6:53 azure linux-2core-8gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=true
6:52 azure linux-2core-8gb TestAccept/bundle/config-remote-sync/multiple_resources/DMS=
6:45 gcp linux-2core-8gb TestAccept/bundle/config-remote-sync/multiple_resources/DMS=true
6:41 azure linux-2core-8gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=
6:39 gcp linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=true
6:38 azure-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=true
6:34 gcp linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=
6:26 gcp linux-2core-8gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=true
6:09 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=
6:01 aws linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=
5:52 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=true
5:48 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DMS=
5:25 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DMS=
5:23 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=true
5:23 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=
5:22 aws-windows-latest-4core-16gb TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=cluster_apply_policy_default_values.yml.tmpl/READPLAN=
5:21 aws linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DMS=
5:20 azure-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=
5:18 aws-windows-latest-4core-16gb TestAccept/bundle/deploy/spark-jar-task/DMS=
5:18 gcp linux-2core-8gb TestAccept/bundle/deploy/spark-jar-task/DMS=true
5:18 azure linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=true
5:08 gcp linux-2core-8gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=
5:08 aws linux-2core-8gb TestAccept/bundle/deploy/spark-jar-task/DMS=
5:07 aws linux-2core-8gb TestAccept/bundle/deploy/spark-jar-task/DMS=true
5:05 aws-windows-latest-4core-16gb TestAccept/bundle/deploy/spark-jar-task/DMS=true
5:03 azure linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=
5:03 azure linux-2core-8gb TestAccept/bundle/deploy/spark-jar-task/DMS=
4:51 gcp linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DMS=true
4:46 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DMS=true
4:43 gcp-windows-latest-4core-16gb TestAccept/bundle/deploy/spark-jar-task/DMS=true
4:35 gcp linux-2core-8gb TestAccept/bundle/deploy/spark-jar-task/DMS=
4:33 azure-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DMS=

@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 4d4ed66

Run: 38756724026

Env ❌​FAIL 🔄​flaky ✅​pass 🙈​skip Time
❌​ aws linux-2core-8gb 31 1494 1130 223:19
❌​ aws-windows-latest-4core-16gb 33 1417 1155 273:06
❌​ azure linux-2core-8gb 12 2 1366 1180 181:25
❌​ azure-windows-latest-4core-16gb 35 1270 1205 196:46
❌​ gcp linux-2core-8gb 22 1329 1190 196:32
❌​ gcp-windows-latest-4core-16gb 37 1239 1215 187:18
83 interesting tests: 83 FAIL
Test Name aws linux-2core-8gb aws-windows-latest-4core-16gb azure linux-2core-8gb azure-windows-latest-4core-16gb gcp linux-2core-8gb gcp-windows-latest-4core-16gb
❌​ TestAccept ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/deploy/spark-jar-task ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/deploy/spark-jar-task/DMS= ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/deploy/spark-jar-task/DMS=true ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/deployment/bind/vector_search_endpoint ❌​F ❌​F ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/deployment/bind/vector_search_endpoint/DMS= ❌​F ❌​F ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/deployment/bind/vector_search_index ❌​F ❌​F ✅​p ❌​F ✅​p ❌​F
❌​ TestAccept/bundle/deployment/bind/vector_search_index/DMS= ❌​F ❌​F ✅​p ❌​F ✅​p ❌​F
❌​ TestAccept/bundle/integration_whl/base ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/integration_whl/base/DMS= ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/integration_whl/base/DMS=true ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/integration_whl/custom_params ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/integration_whl/custom_params/DMS=true ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/integration_whl/interactive_cluster_declared_libs ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/integration_whl/interactive_cluster_declared_libs/DMS= ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version ✅​p ✅​p ✅​p ❌​F ✅​p ❌​F
❌​ TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=SINGLE_USER/DMS=true ✅​p ✅​p ✅​p ❌​F ✅​p ❌​F
❌​ TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=USER_ISOLATION/DMS= ✅​p ✅​p ✅​p ❌​F ✅​p ❌​F
❌​ TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=USER_ISOLATION/DMS=true ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/integration_whl/interactive_single_user ✅​p ✅​p ✅​p ❌​F ✅​p ❌​F
❌​ TestAccept/bundle/integration_whl/interactive_single_user/DMS= ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/integration_whl/interactive_single_user/DMS=true ✅​p ✅​p ✅​p ❌​F ✅​p ❌​F
❌​ TestAccept/bundle/invariant/delete_idempotent ✅​p ✅​p ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=vector_search_endpoint.yml.tmpl/READPLAN= ✅​p ✅​p ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=vector_search_endpoint.yml.tmpl/READPLAN=1 ✅​p ✅​p ✅​p ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=vector_search_index.yml.tmpl/READPLAN= ✅​p ✅​p ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=vector_search_index.yml.tmpl/READPLAN=1 ✅​p ✅​p ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/destroy_idempotent ✅​p ✅​p ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=vector_search_endpoint.yml.tmpl/READPLAN= ✅​p ✅​p ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=vector_search_endpoint.yml.tmpl/READPLAN=1 ✅​p ✅​p ✅​p ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=vector_search_index.yml.tmpl/READPLAN= ✅​p ✅​p ✅​p ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=vector_search_index.yml.tmpl/READPLAN=1 ✅​p ✅​p ✅​p ❌​F ❌​F ✅​p
❌​ TestAccept/bundle/invariant/no_drift ✅​p ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=vector_search_endpoint.yml.tmpl/READPLAN= ✅​p ❌​F 🔄​f ✅​p ❌​F ✅​p
❌​ TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=vector_search_endpoint.yml.tmpl/READPLAN=1 ✅​p ❌​F 🔄​f ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=vector_search_index.yml.tmpl/READPLAN= ✅​p ✅​p ✅​p ❌​F ❌​F ✅​p
❌​ TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=vector_search_index.yml.tmpl/READPLAN=1 ✅​p ✅​p ❌​F ❌​F ❌​F ✅​p
❌​ TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=genie_space.yml.tmpl/READPLAN= ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=vector_search_endpoint.yml.tmpl/READPLAN= ✅​p ❌​F ✅​p ❌​F ❌​F ✅​p
❌​ TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=vector_search_endpoint.yml.tmpl/READPLAN=1 ✅​p ❌​F ✅​p ❌​F ❌​F ✅​p
❌​ TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=vector_search_index.yml.tmpl/READPLAN= ✅​p ❌​F ✅​p ❌​F ❌​F ✅​p
❌​ TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=vector_search_index.yml.tmpl/READPLAN=1 ✅​p ❌​F ✅​p ❌​F ❌​F ✅​p
❌​ TestAccept/bundle/resources/clusters/cluster_policy ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/cluster_policy/DMS=true ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/deploy/data_security_mode ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/deploy/data_security_mode/DMS=true ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/deploy/simple ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/deploy/simple/DMS= ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/deploy/simple/DMS=true ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/deploy/update-after-create ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/deploy/update-after-create/DMS= ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/deploy/update-after-create/DMS=true ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries-repo ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries-repo/DMS=true/READPLAN= ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries-stopped-cluster ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries-stopped-cluster/DMS=/READPLAN=1 ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries-stopped-cluster/DMS=true/READPLAN= ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries-update ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries-update/DMS=/READPLAN=1 ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries-update/DMS=true/READPLAN=1 ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries/DMS=/READPLAN= ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/libraries/DMS=true/READPLAN= ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/lifecycle-started ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/clusters/lifecycle-started/DMS= ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/vector_search_endpoints/basic ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_endpoints/basic/DMS= ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_endpoints/basic/DMS=true ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name/DMS= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name/DMS=true ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/basic ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/basic/DMS= ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/basic/DMS=true ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/grants/select ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/grants/select/DMS= ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/grants/select/DMS=true ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS= ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=true ❌​F ✅​p ✅​p ✅​p ✅​p ❌​F
❌​ TestAccept/bundle/resources/vector_search_indexes/schema_normalization ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/vector_search_indexes/schema_normalization/DMS= ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/vector_search_indexes/schema_normalization/DMS=true ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
Top 50 slowest tests (at least 2 minutes):
duration env testname
26:53 aws-windows-latest-4core-16gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=true
25:23 aws linux-2core-8gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=
24:37 azure linux-2core-8gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=
24:03 aws-windows-latest-4core-16gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=
22:54 azure-windows-latest-4core-16gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=
20:54 azure-windows-latest-4core-16gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=true
20:47 azure linux-2core-8gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=true
20:06 aws linux-2core-8gb TestAccept/bundle/resources/sql_warehouses/lifecycle-started-edit/DMS=true
18:34 gcp linux-2core-8gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=true
16:35 gcp linux-2core-8gb TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension/DMS=
15:32 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/deploy/data_security_mode/DMS=
15:30 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/libraries-stopped-cluster/DMS=true/READPLAN=1
13:56 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/libraries-repo/DMS=/READPLAN=
13:40 gcp linux-2core-8gb TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DMS=true
13:11 aws linux-2core-8gb TestAccept/bundle/integration_whl/custom_params/DMS=
12:14 gcp-windows-latest-4core-16gb TestAccept/bundle/resources/sql_warehouses/lifecycle-started-edit/DMS=
11:55 azure linux-2core-8gb TestAccept/bundle/integration_whl/base/DMS=true
11:36 azure-windows-latest-4core-16gb TestAccept/bundle/integration_whl/interactive_cluster/DMS=
11:19 aws-windows-latest-4core-16gb TestAccept/bundle/resources/model_serving_endpoints/running-endpoint/DMS=true
11:11 azure-windows-latest-4core-16gb TestAccept/bundle/integration_whl/interactive_cluster_declared_libs/DMS=
10:57 azure-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/deploy/data_security_mode/DMS=
10:46 aws-windows-latest-4core-16gb TestAccept/bundle/integration_whl/base/DMS=true
10:22 aws-windows-latest-4core-16gb TestAccept/bundle/resources/model_serving_endpoints/running-endpoint/DMS=
10:07 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=
10:07 azure linux-2core-8gb TestAccept/bundle/integration_whl/interactive_cluster/DMS=
10:07 azure-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/deploy/simple/DMS=true
9:53 azure linux-2core-8gb TestAccept/bundle/integration_whl/interactive_cluster_declared_libs/DMS=true
9:47 gcp linux-2core-8gb TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=USER_ISOLATION/DMS=
9:44 aws-windows-latest-4core-16gb TestAccept/bundle/integration_whl/interactive_single_user/DMS=
9:31 gcp-windows-latest-4core-16gb TestAccept/bundle/integration_whl/interactive_cluster/DMS=true
9:28 gcp-windows-latest-4core-16gb TestAccept/bundle/integration_whl/base/DMS=
9:23 aws linux-2core-8gb TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=USER_ISOLATION/DMS=
9:19 azure-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/lifecycle-started/DMS=true
9:15 gcp-windows-latest-4core-16gb TestAccept/bundle/integration_whl/interactive_cluster/DMS=
9:14 aws-windows-latest-4core-16gb TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=USER_ISOLATION/DMS=
9:11 aws-windows-latest-4core-16gb TestAccept/bundle/integration_whl/interactive_single_user/DMS=true
9:07 azure-windows-latest-4core-16gb TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=SINGLE_USER/DMS=
9:00 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/cluster_policy/DMS=
8:59 aws-windows-latest-4core-16gb TestAccept/bundle/resources/apps/lifecycle-started/DMS=true
8:56 gcp linux-2core-8gb TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=SINGLE_USER/DMS=
8:55 gcp linux-2core-8gb TestAccept/bundle/resources/clusters/run/spark_python_task/DMS=true
8:52 aws-windows-latest-4core-16gb TestAccept/bundle/resources/clusters/libraries-content-change/DMS=true/READPLAN=1
8:50 gcp-windows-latest-4core-16gb TestAccept/bundle/invariant/no_drift/DMS=true/INPUT_CONFIG=cluster_libraries.yml.tmpl/READPLAN=
8:43 azure linux-2core-8gb TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=SINGLE_USER/DMS=true
8:43 gcp linux-2core-8gb TestAccept/bundle/resources/clusters/libraries/DMS=/READPLAN=
8:39 gcp linux-2core-8gb TestAccept/bundle/integration_whl/interactive_single_user/DMS=true
8:39 aws-windows-latest-4core-16gb TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=cluster_apply_policy_default_values.yml.tmpl/READPLAN=1
8:37 gcp linux-2core-8gb TestAccept/bundle/integration_whl/interactive_single_user/DMS=
8:37 gcp linux-2core-8gb TestAccept/bundle/integration_whl/base/DMS=true
8:36 azure linux-2core-8gb TestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATA_SECURITY_MODE=USER_ISOLATION/DMS=true

dhakad22klx pushed a commit to dhakad22klx/cli that referenced this pull request Oct 18, 2026
…mpute (databricks#7063)

## Changes

A serverless `databricks ssh connect` (CPU or `--accelerator`) now reads
the `port_fwd_serverless_enabled` workspace setting first, in
ProxyCommand mode too. When an administrator has turned it off, connect
stops before it creates the secret scope, uploads binaries or submits
the server run:

```
Connecting to my-session...
Error: port forwarding to serverless compute is disabled for this workspace (setting port_fwd_serverless_enabled), and the SSH tunnel needs it. Ask a workspace or account admin to enable it, or connect to a dedicated cluster with --cluster
```

- `checkPortForwardingToServerless` reads the setting with
`WorkspaceSettingsV2.GetPublicWorkspaceSetting` and refuses only when
the read succeeds and `effective_boolean_val` is `false`.
- A read that fails is logged at debug level and connect continues. The
driver proxy's 403 from databricks#7057 then stops it.
- `libs/testserver` answers the settings GET, defaulting
`port_fwd_serverless_enabled` to `true` like the real setting.

## Why

Stacked on databricks#7057, PR 2 of DECO-28889. databricks#7057 makes connect stop on the
driver proxy's 403, but by then it has uploaded binaries and started
serverless compute. The setting is what the proxy enforces, so checking
it first avoids both.

The CLI can't see everything the proxy's gate
(`PortForwardingToServerlessGate`) checks. The gate also needs its
enforcement flag on and skips allow-listed ports, and the setting is
only served through the public API in dev and staging
(`public_api_stage: STAGING`; production answers `Setting
port_fwd_serverless_enabled is not enabled for public API`). So a failed
read is never an error, and the 403 handling stays as the backstop. The
acceptance test for that backstop now stubs the settings read the way
production answers it.

## Tests

- Unit: `TestCheckPortForwardingToServerless` covers disabled, enabled,
no effective value, and a failed read. Plus new
`libs/testserver/settings_test.go` tests.
- Acceptance: new
`acceptance/ssh/connect-serverless-port-forwarding-disabled` checks the
error and that connect sent no requests besides reads.
`connect-serverless-feature-disabled` keeps covering the 403 path, with
the settings read failing. All `acceptance/ssh` tests pass.
- Manual, dogfood, setting off: serverless CPU, `--accelerator
GPU_1xA10`, and ProxyCommand mode (`ssh -o ProxyCommand="databricks ssh
connect --proxy --name …"`) all stop within 1 s with the error above.
- Manual, dogfood, setting on: serverless connects and runs the remote
command.

This pull request and its description were written by Isaac.

---------

Co-authored-by: Isaac <no-reply@databricks.com>
arushiagarwal-db pushed a commit to arushiagarwal-db/cli that referenced this pull request Oct 19, 2026
…es (databricks#7064)

## Changes

Two new `SshTunnelErrorCategory` values for the port forwarding refusals
added in databricks#7057 and databricks#7063:

| Category | Reported when | Before |
|---|---|---|
| `PORT_FORWARDING_DISABLED` | The up-front read of
`port_fwd_serverless_enabled` returns `false`, before any compute is
started | `UNKNOWN` |
| `DRIVER_PROXY_FORBIDDEN` | The driver proxy refuses a request to the
SSH server with a 403, for a server that was already running or for one
that this connection started | `SERVER_START_TIMEOUT` |

Both acceptance tests now also check the `error_category` in the
uploaded telemetry event.

## Why

PR 3 of DECO-28889, after databricks#7057 and databricks#7063. Without these, a disabled
setting shows up as slow server starts or as CLI bugs. Keeping the two
apart shows how often the setting can't be read (production today) and
the proxy's 403 has to catch it.

The backend enum needs the matching values:
https://github.com/databricks-eng/universe/pull/2802257. Either PR can
land first; until the universe one does, ingestion drops these values.

## Tests

- `acceptance/ssh/connect-serverless-port-forwarding-disabled` reports
`PORT_FORWARDING_DISABLED`.
- `acceptance/ssh/connect-serverless-feature-disabled` reports
`DRIVER_PROXY_FORBIDDEN`.
- All `acceptance/ssh` tests and `experimental/ssh/...` unit tests pass.

This pull request and its description were written by Isaac.

---------

Co-authored-by: Isaac <no-reply@databricks.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants